/*
 * Copyright (c) 2024 Black Sesame Technologies
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <chrono>
#include <thread>
#include <gtest/gtest.h>
#include "dal/domain_participant.h"
#include "dal/publisher.h"
#include "dal/subscriber.h"
#include "dal/topic.h"
#include "dal/participant_monitor.h"
#include "dal_rticonnextdds/rtps/GuidUtils.hpp"
#include "dal_rticonnextdds/entity_impl/DalDomainParticipantImpl.hpp"
#include "mj_interfaces/msg/mjtype.hpp"

TEST(domain_participant_impl, test_domain_participant)
{
    dal_ret_t ret;
    dal_domain_participant_listener_callbacks_t callbacks = { };
    dal_domain_participant_listener_t* listener = dal_create_domain_participant_listener(callbacks);

    dal_domain_participant_t* participant =
        dal_create_domain_participant(20, DAL_PARTICIPANT_QOS_DEFAULT, listener, DAL_ANY_STATUS);
    EXPECT_NE(participant->handle_, nullptr);

    ret = dal_delete_domain_participant_listener(listener);
    EXPECT_EQ(ret, DAL_RETCODE_PRECONDITION_NOT_MET);

    ret = dal_delete_domain_participant(participant);
    EXPECT_EQ(ret, DAL_RETCODE_OK);

    ret = dal_delete_domain_participant_listener(listener);
    EXPECT_EQ(ret, DAL_RETCODE_OK);
}

TEST(test_created_entity_with_created_default_qos, test_domain_participant)
{
    dal_ret_t ret;
    dal_domain_participant_qos_t* part_qos = dal_create_default_participant_qos();
    dal_domain_participant_t* participant =
        dal_create_domain_participant(20, part_qos, NULL, DAL_ANY_STATUS);
    EXPECT_NE(participant, nullptr);
    EXPECT_NE(participant->handle_, nullptr);

    dal_type_support_t* ts =
        dal_create_type_support((void*)(mj_interfaces::msg::Mjtype::FullyQualifiedName()));
    ret = dal_type_support_register_type(ts, participant, dal_type_support_get_type_name(ts));
    EXPECT_EQ(ret, DAL_RETCODE_OK);

    dal_topic_listener_callbacks_t topic_callbacks = { };
    dal_topic_listener_t* topic_listener = dal_create_topic_listener(topic_callbacks);
    dal_topic_qos_t* topic_qos = dal_create_default_topic_qos();
    dal_topic_t* topic = dal_domain_participant_create_topic(participant,
                                                             "HelloWorldTopic",
                                                             dal_type_support_get_type_name(ts),
                                                             topic_qos,
                                                             topic_listener,
                                                             DAL_ANY_STATUS);
    EXPECT_NE(topic, nullptr);
    EXPECT_NE(topic->handle_, nullptr);

    ret = dal_domain_participant_delete_topic(participant, topic);
    EXPECT_EQ(ret, DAL_RETCODE_OK);

    dal_delete_topic_qos(topic_qos);

    ret = dal_delete_topic_listener(topic_listener);
    EXPECT_EQ(ret, DAL_RETCODE_OK);

    dal_delete_type_support(ts);
    dal_delete_domain_participant(participant);
    dal_delete_participant_qos(part_qos);
}

TEST(test_domain_participant_with_topic, test_domain_participant)
{
    dal_ret_t ret;
    dal_domain_participant_listener_callbacks_t participant_callbacks = { };

    dal_domain_participant_listener_t* participant_listener =
        dal_create_domain_participant_listener(participant_callbacks);
    EXPECT_NE(participant_listener, nullptr);

    dal_domain_participant_t* participant = dal_create_domain_participant(
        20, DAL_PARTICIPANT_QOS_DEFAULT, participant_listener, DAL_ANY_STATUS);
    EXPECT_NE(participant, nullptr);

    dal_type_support_t* ts =
        dal_create_type_support((void*)(mj_interfaces::msg::Mjtype::FullyQualifiedName()));
    EXPECT_NE(ts, nullptr);

    const char* type_name = dal_type_support_get_type_name(ts);
    ret = dal_type_support_register_type(ts, participant, type_name);
    EXPECT_EQ(ret, DAL_RETCODE_OK);

    dal_topic_listener_callbacks_t topic_callbacks = { };
    dal_topic_listener_t* topic_listener = dal_create_topic_listener(topic_callbacks);
    EXPECT_NE(topic_listener, nullptr);

    dal_topic_t* topic = dal_domain_participant_create_topic(participant,
                                                             "HelloWorldTopic",
                                                             type_name,
                                                             DAL_TOPIC_QOS_DEFAULT,
                                                             topic_listener,
                                                             DAL_ANY_STATUS);
    EXPECT_NE(topic->handle_, nullptr);

    ret = dal_delete_topic_listener(topic_listener);
    EXPECT_EQ(ret, DAL_RETCODE_PRECONDITION_NOT_MET);
    ret = dal_domain_participant_delete_topic(participant, topic);
    EXPECT_EQ(ret, DAL_RETCODE_OK);
    ret = dal_domain_participant_delete_topic(participant, topic);
    EXPECT_NE(ret, DAL_RETCODE_OK);
    ret = dal_delete_topic_listener(topic_listener);
    EXPECT_EQ(ret, DAL_RETCODE_OK);
    ret = dal_delete_domain_participant(participant);
    EXPECT_EQ(ret, DAL_RETCODE_OK);
    ret = dal_delete_domain_participant_listener(participant_listener);
    EXPECT_EQ(ret, DAL_RETCODE_OK);

    dal_delete_type_support(ts);
}

TEST(create_topic_with_wrong_para, test_domain_participant)
{
    dal_ret_t ret;
    dal_domain_participant_t* participant =
        dal_create_domain_participant(20, DAL_PARTICIPANT_QOS_DEFAULT, NULL, DAL_ANY_STATUS);
    EXPECT_NE(participant, nullptr);

    dal_type_support_t* ts =
        dal_create_type_support((void*)(mj_interfaces::msg::Mjtype::FullyQualifiedName()));
    EXPECT_NE(ts, nullptr);

    const char* type_name = dal_type_support_get_type_name(ts);
    ret = dal_type_support_register_type(ts, participant, type_name);
    EXPECT_EQ(ret, DAL_RETCODE_OK);

    dal_topic_t* topic = dal_domain_participant_create_topic(
        participant, "", "", DAL_TOPIC_QOS_DEFAULT, NULL, DAL_ANY_STATUS);
    EXPECT_EQ(topic, nullptr);

    ret = dal_delete_domain_participant(participant);
    EXPECT_EQ(ret, DAL_RETCODE_OK);

    dal_delete_type_support(ts);
}

TEST(delete_listener, test_domain_participant)
{
    dal_ret_t ret;
    dal_domain_participant_listener_callbacks_t participant_callbacks = { };

    dal_domain_participant_listener_t* participant_listener =
        dal_create_domain_participant_listener(participant_callbacks);
    EXPECT_NE(participant_listener, nullptr);

    ret = dal_delete_domain_participant_listener(participant_listener);
    EXPECT_EQ(ret, DAL_RETCODE_OK);

    ret = dal_delete_domain_participant_listener(participant_listener);
    EXPECT_NE(ret, DAL_RETCODE_OK);

    ret = dal_delete_domain_participant_listener(NULL);
    EXPECT_NE(ret, DAL_RETCODE_OK);
}

TEST(delete_type_support, test_domain_participant)
{
    dal_ret_t ret;
    dal_type_support_t* ts =
        dal_create_type_support((void*)(mj_interfaces::msg::Mjtype::FullyQualifiedName()));
    EXPECT_NE(ts, nullptr);

    ret = dal_delete_type_support(ts);
    EXPECT_EQ(ret, DAL_RETCODE_OK);

    ret = dal_delete_type_support(ts);
    EXPECT_EQ(ret, DAL_RETCODE_BAD_PARAMETER);

    ret = dal_delete_type_support(nullptr);
    EXPECT_EQ(ret, DAL_RETCODE_BAD_PARAMETER);
}

TEST(invalid_domainid, test_domain_participant)
{
    dal_domain_participant_t* participant =
        dal_create_domain_participant(-1, DAL_PARTICIPANT_QOS_DEFAULT, NULL, DAL_ANY_STATUS);
    EXPECT_EQ(participant, nullptr);
}

TEST(delete_participant_twice, test_domain_participant)
{
    dal_domain_participant_t* participant =
        dal_create_domain_participant(20, DAL_PARTICIPANT_QOS_DEFAULT, NULL, DAL_ANY_STATUS);
    dal_delete_domain_participant(participant);
    dal_ret_t ret = dal_delete_domain_participant(participant);
    EXPECT_NE(ret, DAL_RETCODE_OK);
}

/*
void monitor_callback(dal_participant_monitor_info_t* monitor_info, void* data)
{
    (void*)data;
    int i;
    std::string participant_name;
    if (monitor_info->participant_name.length) {
        participant_name = std::string(monitor_info->participant_name.str,
monitor_info->participant_name.length);
    }

    switch (monitor_info->status) {
        case DAL_PARTICIPANT_ONLINE:
            std::cout << "[DAL_PARTICIPANT_ONLINE] guid:";
            break;
        case DAL_PARTICIPANT_OFFLINE_NORMALLY:
            std::cout << "[DAL_PARTICIPANT_OFFLINE_NORMALLY] guid:";
            break;
        case DAL_PARTICIPANT_OFFLINE_ABNORMALLY:
            std::cout << "[DAL_PARTICIPANT_OFFLINE_ABNORMALLY] guid:";
            break;
        default:
            break;
    }
    for (i = 0; i < GUIDPREFIX_SIZE; i++) {
        std::cout << std::setfill('0') << std::setw(2)
                  << (int)(monitor_info->guid.guidprefix.value[i]);
    }

    std::cout << " participant_name: " << participant_name << std::endl;
}

TEST(participant_monitor, test_run_monitor)
{
    dal_ret_t ret;
    dal_guid_t participant_guid = { };
    dal_guid_t participant_2_guid = { };
    uint32_t domainID = 20;

    dal_domain_participant_listener_callbacks_t participant_callbacks = { };

    dal_domain_participant_listener_t* participant_listener =
        dal_create_domain_participant_listener(participant_callbacks);

    dal_domain_participant_listener_set_participant_monitor_callback(
        participant_listener, monitor_callback, &domainID);

    dal_domain_participant_t* participant = dal_create_domain_participant(
        domainID, DAL_PARTICIPANT_QOS_DEFAULT, participant_listener, DAL_ANY_STATUS);
    participant_guid = dal_domain_participant_get_guid(participant);

    dal_domain_participant_t* participant_2 =
        dal_create_domain_participant(domainID, DAL_PARTICIPANT_QOS_DEFAULT, nullptr,
DAL_ANY_STATUS);

    participant_2_guid = dal_domain_participant_get_guid(participant_2);

    std::this_thread::sleep_for(std::chrono::seconds(2));

    EXPECT_EQ(dal_guid_is_on_same_host(&participant_guid, &participant_2_guid), 1);
    EXPECT_EQ(dal_guid_is_on_same_process(&participant_guid, &participant_2_guid), 1);
    EXPECT_EQ(dal_guidprefix_is_same(&participant_guid, &participant_2_guid), 0)
        << "guid1: " << convertDalGuidToString(&participant_guid) << "\n"
        << "guid2: " << convertDalGuidToString(&participant_2_guid);

    ret = dal_delete_domain_participant(participant_2);
    EXPECT_EQ(ret, DAL_RETCODE_OK);

    ret = dal_delete_domain_participant(participant);
    EXPECT_EQ(ret, DAL_RETCODE_OK);

    dal_delete_domain_participant_listener(participant_listener);
}

*/


TEST(create_topic_with_same_topic_name, test_domain_participant)
{
    dal_ret_t ret;
    dal_domain_participant_t* participant =
        dal_create_domain_participant(20, DAL_PARTICIPANT_QOS_DEFAULT, NULL, DAL_ANY_STATUS);

    dal_type_support_t* ts =
        dal_create_type_support((void*)(mj_interfaces::msg::Mjtype::FullyQualifiedName()));
    ret = dal_type_support_register_type(ts, participant, dal_type_support_get_type_name(ts));
    EXPECT_EQ(ret, DAL_RETCODE_OK);

    dal_topic_t* topic1 = dal_domain_participant_create_topic(participant,
                                                              "HelloWorldTopic",
                                                              dal_type_support_get_type_name(ts),
                                                              DAL_TOPIC_QOS_DEFAULT,
                                                              NULL,
                                                              DAL_ANY_STATUS);
    EXPECT_NE(topic1, nullptr);
    dal_topic_t* topic2 = dal_domain_participant_create_topic(participant,
                                                              "HelloWorldTopic",
                                                              dal_type_support_get_type_name(ts),
                                                              DAL_TOPIC_QOS_DEFAULT,
                                                              NULL,
                                                              DAL_ANY_STATUS);
    EXPECT_EQ(topic2, nullptr);

    ret = dal_domain_participant_delete_topic(participant, topic1);
    EXPECT_EQ(ret, DAL_RETCODE_OK);

    dal_topic_t* topic3 = dal_domain_participant_create_topic(participant,
                                                              "HelloWorldTopic",
                                                              dal_type_support_get_type_name(ts),
                                                              DAL_TOPIC_QOS_DEFAULT,
                                                              NULL,
                                                              DAL_ANY_STATUS);
    EXPECT_NE(topic3, nullptr);
    ret = dal_domain_participant_delete_topic(participant, topic3);
    EXPECT_EQ(ret, DAL_RETCODE_OK);

    dal_delete_type_support(ts);
    dal_delete_domain_participant(participant);
}

TEST(delete_null_typesupport, test_domain_participant)
{
    dal_ret_t ret = dal_delete_type_support(NULL);
    EXPECT_NE(ret, DAL_RETCODE_OK);
}

TEST(get_ts_name_pass_null_ts, test_domain_participant)
{
    const char* type_name = dal_type_support_get_type_name(nullptr);
    EXPECT_EQ(type_name, nullptr);
}